package com.gitee.feizns.quickstart.ali.yun.oss;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.CannedAccessControlList;
import com.aliyun.oss.model.ListObjectsRequest;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.OSSObjectSummary;
import com.aliyun.oss.model.ObjectListing;
import com.aliyun.oss.model.PutObjectResult;
import com.aliyun.oss.model.SetObjectAclRequest;
import com.aliyun.oss.model.VoidResult;
import lombok.Getter;

import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import java.util.stream.Stream;

/**
 * 阿里云OSS SDK工具类
 * @link <a href="https://help.aliyun.com/document_detail/32007.html?spm=a2c4g.11186623.0.0.4f3d3666XwLA8I">对象存储 OSS>SDK示例>Java</a>
 * @author feizns
 * @since 2023/3/1
 */
@Getter
public class AliYunOssUtils {

    /**
     * {@link AliYunOssConfig}
     */
    private final AliYunOssConfig config;

    /**
     * {@link OSS}
     */
    private final OSS oss;

    /**
     * {@link AliYunOssConfig}
     * @param config {@link AliYunOssConfig}
     */
    public AliYunOssUtils(AliYunOssConfig config) {
        this.config = config;
        oss = new OSSClientBuilder().build(config.getEndpoint(), config.getAccessKeyId(), config.getAccessKeySecret());
    }

    /**
     * 获取文件内容
     * @param key 文件目录+名称
     * @return {@link InputStream}
     */
    public OSSObject get(String key) {
        return oss.getObject(config.getBucketName(), key);
    }

    /**
     * 上传文件
     * @param key 文件目录+名称
     * @param is {@link InputStream}
     * @return {@link PutObjectResult}
     */
    public PutObjectResult put(String key, InputStream is) {
        return oss.putObject(config.getBucketName(), key, is);
    }

    /**
     * 上传文件
     * @param key 上传文件的同时指定访问权限
     * @param is 文件内容
     * @param accessControl {@link CannedAccessControlList}
     * @return {@link PutObjectResult}
     */
    public PutObjectResult put(String key, InputStream is, CannedAccessControlList accessControl) {
        PutObjectResult result = put(key, is);
        oss.setObjectAcl(new SetObjectAclRequest(config.getBucketName(), key, accessControl));
        return result;
    }

    /**
     * 删除文件
     * @param key 钥匙
     * @return {@link Object }
     */
    public VoidResult del(String key) {
        return oss.deleteObject(config.getBucketName(), key);
    }

    /**
     * 生成OSS的有效时长
     * <p>
     *     生成以GET方法访问的签名URL，访客可以直接通过浏览器访问相关内容。
     * </p>
     * @param key 文件名
     * @param expiration 设置签名URL过期时间，单位为毫秒。
     * @return {@link URL}
     */
    public URL generatePreSignedUrl(String key, long expiration) {
        return oss.generatePresignedUrl(config.getBucketName(), key, new Date(System.currentTimeMillis() + expiration));
    }

    /**
     * 列举出指定前缀的oss 对象key列表
     * @return {@link ObjectListing}
     */
    public Stream<OSSObjectSummary> listObjects(String prefix, int maxKeys) {
        Stream.Builder<OSSObjectSummary> builder = Stream.builder();
        String nextMarker = null;
        ObjectListing objectListing;
        do {
            ListObjectsRequest request = new ListObjectsRequest(config.getBucketName())
                    .withPrefix(prefix)
                    .withMarker(nextMarker)
                    .withMaxKeys(maxKeys);
            objectListing = oss.listObjects(request);
            objectListing.getObjectSummaries().forEach(builder::add);
            nextMarker = objectListing.getNextMarker();
        } while ( objectListing.isTruncated() );
        return builder.build();
    }

}
